----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    16:35:26 11/04/2014 
-- Design Name: 
-- Module Name:    Hermitian_conj - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity Hermitian_conj is
	 generic ( memAddrWidth : integer :=  7 ); 
    Port ( clk : in  STD_LOGIC;
           ce : in  STD_LOGIC;
           SymIn : in  STD_LOGIC_VECTOR (7 downto 0);
           dataAvailable_in : in  STD_LOGIC;
           SymOut : out  STD_LOGIC_VECTOR (7 downto 0);
           dataAvailable_out : out  STD_LOGIC;
			  outDataLast : out  STD_LOGIC;
           dataInReady : out  STD_LOGIC);
end Hermitian_conj;

architecture Behavioral of Hermitian_conj is

signal sig_SymIn_z1 : STD_LOGIC_VECTOR (7 downto 0) := (others => '0');
signal sig_SymIn_z2 : STD_LOGIC_VECTOR (7 downto 0) := (others => '0');
signal sig_SymOut : STD_LOGIC_VECTOR (7 downto 0) := (others => '0');

signal sig_FreqBandCtrl_rd_addr : STD_LOGIC_VECTOR(memAddrWidth - 1 DOWNTO 0) := (others => '0');

signal sig_rom_end_addr : STD_LOGIC_VECTOR(memAddrWidth - 1 DOWNTO 0) := (others => '1');
signal sig_rom_rd_addr : STD_LOGIC_VECTOR(memAddrWidth - 1 DOWNTO 0) := (others => '0');
signal sig_rom_rd_data : STD_LOGIC_VECTOR(8 DOWNTO 0) := (others => '0');

signal sig_ram_wr_addr : STD_LOGIC_VECTOR(memAddrWidth - 1 DOWNTO 0) := (others => '0');
signal sig_ram_wr_data : STD_LOGIC_VECTOR(7 DOWNTO 0) := (others => '0');
signal sig_ram_rd_addr : STD_LOGIC_VECTOR(memAddrWidth - 1 DOWNTO 0) := (others => '0');
signal sig_wr_en : STD_LOGIC := '0';
signal sig_rd_en : STD_LOGIC := '0';
signal sig_ram_out : STD_LOGIC_VECTOR(7 DOWNTO 0) := (others => '0');

signal sig_ram_end_addr : STD_LOGIC_VECTOR(memAddrWidth - 1 DOWNTO 0) := (others => '1');	
signal sig_hermitian_addr_wr : STD_LOGIC_VECTOR(memAddrWidth - 1 DOWNTO 0) := sig_ram_end_addr;	
signal sig_hermitian_addr_rd : STD_LOGIC_VECTOR(memAddrWidth - 1 DOWNTO 0) := (others => '0');
signal sig_hermitian_addr_rd_z1 : STD_LOGIC_VECTOR(memAddrWidth - 1 DOWNTO 0) := (others => '0');
signal sig_hermitian_addr_rd_z2 : STD_LOGIC_VECTOR(memAddrWidth - 1 DOWNTO 0) := (others => '0');

type symbol_states is (idle, normal, conj);
signal sym_states : symbol_states := idle;

component FreqBandCtrl_mem IS
  PORT (
    clka : IN STD_LOGIC;
    addra : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
    douta : OUT STD_LOGIC_VECTOR(8 DOWNTO 0)
  );
END component FreqBandCtrl_mem;

component HermitianConj_mem IS
  PORT (
    a : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
    d : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
    dpra : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
    clk : IN STD_LOGIC;
    we : IN STD_LOGIC;
    i_ce : IN STD_LOGIC;
    qdpo_ce : IN STD_LOGIC;
    qdpo : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
  );
END component HermitianConj_mem;

begin

FreqBandCtrl : FreqBandCtrl_mem
PORT map (
 clka => clk,
 addra => sig_rom_rd_addr,
 douta => sig_rom_rd_data
);

HermitianConj : HermitianConj_mem
PORT map (
    a => sig_ram_wr_addr,
    d => sig_ram_wr_data,
    dpra => sig_ram_rd_addr,
    clk => clk,
    we => '1',
    i_ce => sig_wr_en,
    qdpo_ce => sig_rd_en,
    qdpo => sig_ram_out
);

process(clk, ce, sym_states)
begin 
	if (rising_edge(clk)) then
		case sym_states is
			when idle =>		
				if (dataAvailable_in = '1') then
					sym_states <= normal;
				end if;
				
			when normal =>
				if (ce='1') then	
				
					if (unsigned(sig_FreqBandCtrl_rd_addr) >= unsigned(sig_rom_end_addr)) then
						sig_FreqBandCtrl_rd_addr <= (others=>'0');
					else
						sig_FreqBandCtrl_rd_addr <= std_logic_vector(unsigned(sig_FreqBandCtrl_rd_addr) + 1);
					end if;
					
					if (unsigned(sig_hermitian_addr_wr) <= 0) then
						sig_hermitian_addr_wr <= sig_ram_end_addr;
						sym_states <= conj;
					else
						sig_hermitian_addr_wr <= std_logic_vector(unsigned(sig_hermitian_addr_wr) - 1);
					end if;		
				end if;
				
			when conj =>
				if (ce='1') then
					if (unsigned(sig_hermitian_addr_rd) >= unsigned(sig_ram_end_addr)) then
						sig_hermitian_addr_rd <= (others => '0');
						sym_states <= normal;
					else
						sig_hermitian_addr_rd <= std_logic_vector(unsigned(sig_hermitian_addr_rd) + 1);
					end if;	
				end if;
				
		end case;
	end if;
end process;

process(clk, sym_states)
begin
	if (rising_edge(clk)) then
	
		sig_SymIn_z1 <= SymIn;
		sig_SymIn_z2 <= sig_SymIn_z1;
		
		outDataLast <= '0';
		
		case sym_states is
			when idle =>
				dataInReady <= '1';
				dataAvailable_out <= '0';
				sig_wr_en <= '0';
				sig_rd_en <= '0';
				
			when normal =>
--				dataInReady <= '1';
				dataAvailable_out <= '1';
				sig_wr_en <= '1';
				sig_rd_en <= '0';

				sig_rom_rd_addr <= sig_FreqBandCtrl_rd_addr;
				if (sig_rom_rd_data(0) = '1') then
					sig_SymOut <= sig_rom_rd_data(8 downto 1);
					dataInReady <= '0';
				else
					sig_SymOut <= sig_SymIn_z2;
					dataInReady <= '1';
				end if;
				
				sig_ram_wr_addr <= sig_hermitian_addr_wr;				
				if (unsigned(sig_hermitian_addr_wr) = unsigned(sig_ram_end_addr)) then
					sig_ram_wr_data <= (others=>'0');
				else
					sig_ram_wr_data <= sig_SymOut(7 downto 4) & std_logic_vector(unsigned(not(sig_SymOut(3 downto 0))) + 1);
				end if;
				
			when conj =>
				dataInReady <= '0';
				dataAvailable_out <= '1';
				sig_wr_en <= '0';
				sig_rd_en <= '1';
				
				if (unsigned(sig_hermitian_addr_rd) = 0) then
--					sig_ram_rd_addr <= sig_hermitian_addr_rd; 
				else
					sig_ram_rd_addr <= std_logic_vector(unsigned(sig_hermitian_addr_rd) - 1);
				end if;
				
				sig_hermitian_addr_rd_z1 <= sig_hermitian_addr_rd;
				sig_hermitian_addr_rd_z2 <= sig_hermitian_addr_rd_z1;
				
				if (unsigned(sig_hermitian_addr_rd) = 0) then
					sig_SymOut <= (others=>'0');
				elsif (unsigned(sig_hermitian_addr_rd_z2) > 0) then
					sig_SymOut <= sig_ram_out;
					if (unsigned(sig_hermitian_addr_rd_z2) = unsigned(sig_ram_end_addr)) then
						outDataLast <= '1';
					end if;		
				end if;				
				
		end case;
	end if;
end process;

SymOut <= sig_SymOut;

end Behavioral;

